package dshttp

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"gitee.com/deep-sea-tech/ds-go-client/dsregistry"
)

type Client struct {
	Registry *dsregistry.RedisRegistry
	Service  string        `yaml:"service"`
	Domain   string        `yaml:"domain"`
	Strategy string        `yaml:"strategy"`
	Timeout  time.Duration `yaml:"timeout"`
	Http     *http.Client
}

// New 创建客户端
func New(serviceName, strategy string) *Client {
	return &Client{
		Registry: dsregistry.RegistryCenterInstance,
		Service:  serviceName,
		Strategy: strategy,
		Timeout:  5 * time.Second,
		Http:     &http.Client{Timeout: 5 * time.Second},
	}
}

func (c *Client) WithTimeout(d time.Duration) *Client {
	c.Timeout = d
	c.Http.Timeout = d
	return c
}

type Request struct {
	client  *Client
	method  string
	path    string
	query   url.Values
	headers map[string]string
	body    []byte
	cookies []*http.Cookie
	resp    *http.Response
	err     error
}

// NewRequest 创建请求
func (c *Client) NewRequest(method, path string) *Request {
	return &Request{
		client:  c,
		method:  method,
		path:    path,
		query:   url.Values{},
		headers: map[string]string{},
	}
}

func (c *Client) Get(path string) *Request    { return c.NewRequest(http.MethodGet, path) }
func (c *Client) Post(path string) *Request   { return c.NewRequest(http.MethodPost, path) }
func (c *Client) Put(path string) *Request    { return c.NewRequest(http.MethodPut, path) }
func (c *Client) Delete(path string) *Request { return c.NewRequest(http.MethodDelete, path) }

// 链式构造部分 ↓↓↓

func (r *Request) Query(params map[string]any) *Request {
	for k, v := range params {
		r.query.Set(k, fmt.Sprintf("%v", v))
	}
	return r
}

func (r *Request) Header(key, val string) *Request {
	r.headers[key] = val
	return r
}

func (r *Request) BodyJSON(data any) *Request {
	if r.err != nil {
		return r
	}
	j, err := json.Marshal(data)
	if err != nil {
		r.err = err
		return r
	}
	r.body = j
	r.headers["Content-Type"] = "application/json"
	return r
}

// Do 发送请求并获取原始响应
func (r *Request) Do() *Request {
	if r.err != nil {
		return r
	}
	inst, err := r.client.Registry.SelectInstance(r.client.Service, r.client.Strategy)
	if err != nil {
		r.err = fmt.Errorf("select instance error: %w", err)
		return r
	}

	uri := fmt.Sprintf("%s://%s:%d%s", inst.Protocol, inst.Address, inst.Port, r.path)
	if len(r.query) > 0 {
		if strings.Contains(uri, "?") {
			uri += "&" + r.query.Encode()
		} else {
			uri += "?" + r.query.Encode()
		}
	}

	req, err := http.NewRequest(r.method, uri, bytes.NewReader(r.body))
	if err != nil {
		r.err = err
		return r
	}

	// 注入 Header
	for k, v := range r.headers {
		req.Header.Set(k, v)
	}

	// 注入 Cookie
	for _, ck := range r.cookies {
		req.AddCookie(ck)
	}

	resp, err := r.client.Http.Do(req)
	if err != nil {
		r.err = fmt.Errorf("request failed: %w", err)
		return r
	}
	if resp.StatusCode >= 500 {
		msg, _ := io.ReadAll(resp.Body)
		resp.Body.Close()
		r.err = fmt.Errorf("server error: %s", string(msg))
		return r
	}
	r.resp = resp
	return r
}

// Bind 自动解析 JSON 到结构体
func (r *Request) Bind(out any) *Request {
	if r.err != nil {
		return r
	}
	defer r.resp.Body.Close()
	if err := json.NewDecoder(r.resp.Body).Decode(out); err != nil {
		r.err = fmt.Errorf("json decode failed: %w", err)
	}
	return r
}

// Err 返回错误
func (r *Request) Err() error {
	return r.err
}

// RawResponse 获取原始响应
func (r *Request) RawResponse() *http.Response {
	return r.resp
}

// Cookie 添加 Cookie
func (r *Request) Cookie(cookie *http.Cookie) *Request {
	r.cookies = append(r.cookies, cookie)
	return r
}

// Cookies 添加多个 Cookie
func (r *Request) Cookies(cookies ...*http.Cookie) *Request {
	r.cookies = append(r.cookies, cookies...)
	return r
}

// RawBody 直接设置原始 Body（如表单、xml、文本）
func (r *Request) RawBody(data []byte, contentType string) *Request {
	r.body = data
	r.headers["Content-Type"] = contentType
	return r
}

// Method 设置 HTTP 方法（用于 PATCH、OPTIONS、HEAD 等）
func (r *Request) Method(method string) *Request {
	r.method = method
	return r
}
